//
//  ZZ.swift
//  AliIndexEffect
//
//  Created by 陈钟 on 2019/12/9.
//  Copyright © 2019 陈钟. All rights reserved.
//

import UIKit

public extension UIScrollView {
    private func makeReplaceDeinit() {
        DispatchQueue.once {
            let originalSelector = Selector(("deinit"))
            let swizzledSelector = Selector(("zz_deinit"))
            
            guard let originalMethod = class_getInstanceMethod(object_getClass(self), originalSelector),
                  let swizzledMethod = class_getInstanceMethod(object_getClass(self), swizzledSelector) else { return }
            
            let didAddMethod = class_addMethod(object_getClass(self), originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))
            
            if didAddMethod {
                class_replaceMethod(object_getClass(self), swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
            } else {
                method_exchangeImplementations(originalMethod, swizzledMethod)
            }
        }
    }
    
    func zz_deinit() {
        self.removeObserver()
        self.zz_deinit()
        ZZLog("do zz_deinit")
    }
    
    private var topViewOldValue: UIView?{
        set{
            let key: UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "topViewOldValue".hashValue)
            objc_setAssociatedObject(self, key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            self.refreshFrame()
        }
        get{
            let key: UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "topViewOldValue".hashValue)
            let obj = objc_getAssociatedObject(self, key)
            return obj as? UIView
        }
    }
    
    /// 设置顶部显示的窗体 将在设置zz_headerViewHeight后自动调整高度 宽度将自动调整
    var zz_topView: UIView?{
        set{
            self.topViewOldValue?.removeFromSuperview()
            if newValue == nil {
                self.removeObserver()
            }else{
                self.addObserver()
            }
            self.topViewOldValue = newValue
        }
        get{
            return self.topViewOldValue
        }
    }

    @discardableResult
    func zz_topView(_ view: UIView?) -> Self {
        zz_topView = view
        return self
    }

    /// 顶部窗体的显示高度
    var zz_topViewHeight: CGFloat{
        set{
            let key: UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "zz_topViewHeight".hashValue)
            objc_setAssociatedObject(self, key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)

            self.contentInset = UIEdgeInsets(top: newValue, left: 0, bottom: 0, right: 0)
            self.scrollIndicatorInsets = UIEdgeInsets(top: newValue, left: 0, bottom: 0, right: 0)
            self.contentOffset = CGPoint(x: 0, y: -newValue)

            self.refreshFrame()
        }
        get{
            let key: UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "zz_topViewHeight".hashValue)
            let obj = objc_getAssociatedObject(self, key)
            return (obj as? CGFloat) ?? 0
        }
    }
    

    @discardableResult
    func zz_topViewHeight(_ value: CGFloat) -> Self {
        zz_topViewHeight = value
        return self
    }
    /// 顶部窗体的显示宽度
    var zz_topViewWidth: CGFloat{
        set{
            let key: UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "zz_topViewWidth".hashValue)
            objc_setAssociatedObject(self, key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            self.refreshFrame()
        }
        get{
            let key: UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "zz_topViewWidth".hashValue)
            let obj = objc_getAssociatedObject(self, key)
            return (obj as? CGFloat) ?? 0
        }
    }


    @discardableResult
    func zz_topViewWidth(_ value: CGFloat) -> Self {
        zz_topViewWidth = value
        return self
    }


    /// 窗体拖出显示区域后 固定显示高度（高度由窗体底部向上计算）
    var zz_topViewShowHeight: CGFloat{
        set{
            let key: UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "zz_topViewShowHeight".hashValue)
            objc_setAssociatedObject(self, key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)

            self.refreshFrame()
        }
        get{
            let key: UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "zz_topViewShowHeight".hashValue)
            let obj = objc_getAssociatedObject(self, key)
            return (obj as? CGFloat) ?? 0
        }
    }
    
    @discardableResult
    func zz_topViewShowHeight(_ value: CGFloat) -> Self {
        zz_topViewShowHeight = value
        return self
    }

    /// 是否向下拖动的时候 topview一直处于顶部
    var isBindingTop: Bool {
        set{
            let key: UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "isBindingTop".hashValue)
            objc_setAssociatedObject(self, key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        get{
            let key: UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "isBindingTop".hashValue)
            let obj = objc_getAssociatedObject(self, key)
            return (obj as? Bool) ?? true
        }
    }

    @discardableResult
    func isBindingTop(_ value: Bool) -> Self{
        isBindingTop = value
        return self
    }

    /// 监听UIScrollView的大小变更 和 contentOffset变更
    private func addObserver(){
        makeReplaceDeinit()
//        self.addObserver(self, forKeyPath: "frame", options: [.new,.old], context: nil)
//        self.addObserver(self, forKeyPath: "bounds", options: [.new,.old], context: nil)
//        self.addObserver(self, forKeyPath: "contentOffset", options: [.new,.old], context: nil)
        self.addObservers(keyPaths: ["frame","bounds","contentOffset"]) { [weak self]  (_) in
            self?.refreshFrame()
        }
        
    }
    private func removeObserver(){
        self.remoAllObservers()
//        self.removeObserver(self, forKeyPath: "frame")
//        self.removeObserver(self, forKeyPath: "bounds")
//        self.removeObserver(self, forKeyPath: "contentOffset")
    }

    /// 刷新zz_headerView frame
    private func refreshFrame(){
        guard let headerView = self.zz_topView else { return }
        self.addSubview(headerView)

        var h_Frame = CGRect(x: 0, y: 0, width: (self.zz_topViewWidth == 0) ? self.frame.width : self.zz_topViewWidth, height: self.zz_topViewHeight)
        h_Frame.x = (self.frame.width - h_Frame.width) / 2.0
        let offsetY = self.contentOffset.y
        if offsetY <= -self.zz_topViewHeight {
            h_Frame.origin.y = self.isBindingTop ? offsetY : -self.zz_topViewHeight
        }else if (offsetY >= -self.zz_topViewShowHeight){
//            if offsetY > 0 {
//                self.contentInset = UIEdgeInsets(top: self.zz_headerViewShowHeight, left: 0, bottom: 0, right: 0)
//            }else{
//                self.contentInset = UIEdgeInsets(top: self.zz_headerViewHeight, left: 0, bottom: 0, right: 0)
//            }
            h_Frame.origin.y = offsetY - (self.zz_topViewHeight - self.zz_topViewShowHeight)
        }else{
            h_Frame.origin.y = -self.zz_topViewHeight
        }

        headerView.frame = h_Frame
    }

//    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
//        switch keyPath {
//            case "frame","bounds","contentOffset":
//                self.refreshFrame()
//                break
//            default: break
//        }
//    }
}
